#include "sock_message_outlet_service.h"

#include <sstream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>

#include "sock_connection.h"
#include "uid_sock_conn_map.h"
#include "base/json_escape.h"
#include <time.h>
#include <iomanip>

#include "im/adapters/connection_manager_adapter.h"
#include "im/adapters/push_adapter.h"
#include "im/adapters/UserInfoAdapter.h"

namespace imserver {

extern boost::asio::io_service g_io_service;
extern std::string g_outer_endpoint;

class SockMessageOutletTask : public boost::enable_shared_from_this<SockMessageOutletTask> {
public:
  SockMessageOutletTask(const std::set<int64_t>& uids, const ImMessage& message) : uids_(uids), message_(message) {}

  void Handle(int64_t uid, SockConnectionPtr conn) {
    LOG_INFO("MessageOutletTask::Handle --> receiver:" << uid);
    user::UserBaseInfo userInfo;
    try {
      user::UserAdapter::Instance().getUserBasicInfo(userInfo, message_.sender);
    } catch(std::exception& e) {
      LOG_ERROR("SockMessageOutletTask::Handle --> error:" << e.what() << " uid:" << uid);
    }
    std::ostringstream os;
    os << "{\"mid\":" << message_.id
        << ",\"type\":" << message_.type
        << ",\"from\":" << message_.sender
        << ",\"fromname\":\"" << userInfo.nick_name << "\""
        << ",\"fromimg\":\"" << userInfo.photo_url << "\""
        << ",\"time\":" << message_.timestamp
        << ",\"body\":\"" << base::JsonEscape(message_.body) << "\""
        << ",\"did\":" << message_.dialogue_id
        << "}" << IM_RES_END;
    std::string res = os.str();
    LOG_INFO("SockMessageOutletTask::Handle --> res:" << res);
    conn->WriteResponse(res);
  }

  void Start() {
    std::set<int64_t>::const_iterator it = uids_.begin();
    for (; it != uids_.end(); ++it) {
      SockConnectionPtr conn;
      if (UidSockConnMap::instance().get(*it, conn) && conn->isReadyForReceiveMsg()) {
        g_io_service.post(boost::bind(&SockMessageOutletTask::Handle, shared_from_this(), *it, conn));
      } else {
        if (message_.type != ImMessageType::IM_MESSAGE_TYPING && 
            message_.type != ImMessageType::IM_MESSAGE_GROUP &&
            message_.type != ImMessageType::IM_MESSAGE_GROUP_JOIN) {
          PushAdapter::instance().Push(message_.receiver, "您有一条新的消息！", message_.timestamp);
        }

        if (!UidSockConnMap::instance().get(*it, conn)) {
          std::set<int64_t> uids_t;
          uids_t.insert(*it);
          ConnectionManagerAdapter::instance().RemoveSockServiceKeyByUids(uids_t);
        }
      }
    }
  }

private:
  std::set<int64_t> uids_;
  ImMessage message_;
};

void SockMessageOutletServiceHandler::DistributeMessage(const std::set<int64_t>& uids, const ImMessage& message) {
  boost::shared_ptr<SockMessageOutletTask> task(new SockMessageOutletTask(uids, message));
  task->Start();
}

void SockMessageOutletServiceHandler::KickCurrentConn(int64_t uid) {
  SockConnectionPtr conn;
  if (UidSockConnMap::instance().get(uid, conn)) {
    std::ostringstream os;
    os << "{\"type:\":" << ImMessageType::IM_MESSAGE_LOGIN
        << ",\"status\":2"
        << ",\"body\":\"" + g_ImServiceCommon_constants.IM_MESSAGE_KICK_BODY + "\"}" << IM_RES_END;
    std::string kick_msg(os.str());
    conn->WriteKickMsgAndClose(kick_msg.c_str(), kick_msg.size());
    UidSockConnMap::instance().remove(uid);
  }
}

void SockMessageOutletServiceHandler::GetOuterIPAndPort(std::string& _ret) {
  _ret = g_outer_endpoint;
}

}

